package com.myrpc.provider.netty;

import java.lang.reflect.Method;

import org.springframework.beans.factory.annotation.Autowired;

import com.alibaba.fastjson.JSON;
import com.myrpc.common.vo.Request;
import com.myrpc.common.vo.Response;
import com.myrpc.provider.utils.SpringContextHolder;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ServerHandler extends SimpleChannelInboundHandler<String> {
	@Autowired
	SpringContextHolder springContextHolder;

	@Override
	protected void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception {

		Request request = JSON.parseObject(msg, Request.class);
		log.info("channelRead result{}", request);

		log.info("RPC客户端请求接口: {},method{},", request.getClassName(), request.getMethodName());
		Response response = new Response();
		response.setRequestId(request.getId());
		try {
			log.info(JSON.toJSONString(request));
			Object result = this.handler(request);
			log.info("result：{}", JSON.toJSONString(result));
			response.setData(result);
		} catch (Throwable e) {
			e.printStackTrace();
			response.setCode(1);
			response.setError_msg(e.toString());
			log.error("RPC Server handle request error", e);
		}
		ctx.writeAndFlush(JSON.toJSONString(response));

	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		super.channelRead(ctx, msg);
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		System.out.println("exceptionCaught");
		cause.printStackTrace();
		super.exceptionCaught(ctx, cause);
	}

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		log.info("channelActive");
		super.channelActive(ctx);
	}

	/**
	 * 通过反射，执行本地方法
	 * 
	 * @param request
	 * @return
	 * @throws Throwable
	 */
	private Object handler(Request request) throws Throwable {
		String className = request.getClassName();
		log.info("className:{}, request.getServiceId(){}", className, request.getServiceId());
		Object serviceBean = springContextHolder.getBeanById(request.getServiceId());

		if (serviceBean != null) {
			Class<?> serviceClass = serviceBean.getClass();
			String methodName = request.getMethodName();
			Class<?>[] parameterTypes = request.getParameterTypes();
			Object[] parameters = request.getParameters();

			Method method = serviceClass.getMethod(methodName, parameterTypes);
			method.setAccessible(true);
			return method.invoke(serviceBean, getParameters(parameterTypes, parameters));
		} else {
			throw new Exception("未找到服务接口,请检查配置!:" + className + "#" + request.getMethodName());
		}
	}

	/**
	 * 获取参数列表
	 * 
	 * @param parameterTypes
	 * @param parameters
	 * @return
	 */
	private Object[] getParameters(Class<?>[] parameterTypes, Object[] parameters) {
		if (parameters == null || parameters.length == 0) {
			return parameters;
		} else {
			Object[] new_parameters = new Object[parameters.length];
			for (int i = 0; i < parameters.length; i++) {
				new_parameters[i] = JSON.parseObject(parameters[i].toString(), parameterTypes[i]);
			}
			return new_parameters;
		}
	}

}
